package com.secure.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.http.MediaType;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;

/**
 * 请求工具类
 *
 * @author duchao
 */
public class RequestUtil {

    /**
     * 获取当前请求上下文请求对象
     *
     * @return
     */
    public static HttpServletRequest getCurrentRequest() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return attributes.getRequest();
    }

    /**
     * 获取当前请求上下文响应对象
     *
     * @return
     */
    public static HttpServletResponse getCurrentResponse() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return attributes.getResponse();
    }

    /**
     * 获取请求头
     *
     * @return
     */
    public static String getRequestHeader(String requestHeader) {
        return getCurrentRequest().getHeader(requestHeader);
    }

    /**
     * 获取当前请求路径
     *
     * @return
     */
    public static String getCurrentRequestServletPath() {
        return getCurrentRequest().getServletPath();
    }

    /**
     * 获取带boundary的form-data内容类型
     * multipart/form-data请求填充boundary
     *
     * @return
     */
    public static String getFormDataContentTypeWithBoundary() {
        final byte[] boundary = MimeTypeUtils.generateMultipartBoundary();
        Map<String, String> parameters = Collections.singletonMap("boundary", new String(boundary, StandardCharsets.UTF_8));
        MediaType mediaType = new MediaType(MediaType.MULTIPART_FORM_DATA, parameters);
        return mediaType.toString();
    }

    /**
     * 获取处理器方法
     *
     * @param handlerMethods 处理器方法
     * @param servletPath    请求路径
     * @return
     */
    public static HandlerMethod getHandlerMethod(Map<RequestMappingInfo, HandlerMethod> handlerMethods, String servletPath) {
        if (CollectionUtil.isEmpty(handlerMethods)) {
            return null;
        }
        HandlerMethod handlerMethod = null;
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
            RequestMappingInfo requestMappingInfo = entry.getKey();
            if (requestMappingInfo.getPatternValues().stream().anyMatch(pattern -> PathUtil.isMatch(pattern, servletPath))) {
                handlerMethod = entry.getValue();
                break;
            }
        }
        return handlerMethod;
    }

    /**
     * 判断是否是body体传参请求
     *
     * @param handlerMethods 处理器方法
     * @param request    请求
     * @return
     */
    public static boolean isBodyRequest(Map<RequestMappingInfo, HandlerMethod> handlerMethods, HttpServletRequest request) {
        HandlerMethod handlerMethod = getHandlerMethod(handlerMethods, request.getServletPath());
        Annotation[][] parameterAnnotations = handlerMethod.getMethod().getParameterAnnotations();
        if (ArrayUtil.isEmpty(parameterAnnotations)) {
            return false;
        }
        return Arrays.stream(parameterAnnotations).anyMatch(annotations -> Arrays.stream(annotations).anyMatch(annotation -> annotation.annotationType().equals(RequestBody.class)));
    }

    /**
     * 判断是否是body体传参请求
     *
     * @param method 方法
     * @return
     */
    public static boolean isBodyRequest(Method method) {
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        if (ArrayUtil.isEmpty(parameterAnnotations)) {
            return false;
        }
        return Arrays.stream(parameterAnnotations).anyMatch(annotations -> Arrays.stream(annotations).anyMatch(annotation -> annotation.annotationType().equals(RequestBody.class)));
    }

    /**
     * 是否是请求头原内容类型
     *
     * @param contentType 内容类型
     * @return
     */
    public static boolean isBodyRawContentTpe(String contentType) {
        if (MediaType.ALL_VALUE.equals(contentType)) {
            return true;
        }

        return contentType.contains(MediaType.APPLICATION_JSON_VALUE)
                || contentType.contains(MediaType.TEXT_PLAIN_VALUE)
                || contentType.contains(MediaType.TEXT_HTML_VALUE)
                || contentType.contains(MediaType.APPLICATION_XML_VALUE);
    }

    /**
     * 是否是请求头原内容类型
     *
     * @param requestWrapper 请求封装
     * @return
     */
    public static boolean isBodyRawContentTpe(HttpServletRequestWrapper requestWrapper) throws IOException {
        String contentType = requestWrapper.getContentType();
        if (StrUtil.isBlank(contentType)) {
            return false;
        }
        if (MediaType.ALL_VALUE.equals(contentType)) {
            return true;
        }

        String body = StreamUtils.copyToString(requestWrapper.getInputStream(), StandardCharsets.UTF_8);
        return contentType.contains(MediaType.APPLICATION_JSON_VALUE)
                || contentType.contains(MediaType.TEXT_PLAIN_VALUE)
                || contentType.contains(MediaType.TEXT_HTML_VALUE)
                || contentType.contains(MediaType.APPLICATION_XML_VALUE)
                || contentType.contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE) && StrUtil.isNotBlank(body);
    }

}
